# -*- coding: utf-8 -*-
import urllib, md5
# try to use simplejson first, otherwise fallback to XML
RESPONSE_FORMAT = 'JSON'
try:
    import json as simplejson
except ImportError:
    try:
        import simplejson
    except ImportError:
        try:
            from django.utils import simplejson
        except ImportError:
            try:
                import jsonlib as simplejson
                simplejson.loads
            except (ImportError, AttributeError):
                RESPONSE_FORMAT = 'XML'
                
from django.conf import settings
from django.http import HttpRequest

XIAONEI_URL = 'http://api.xiaonei.com/restserver.do'
API_VERSION = '1.0'
    
class ArgumentRequiredError(Exception): pass
class json(object): pass
class comma_separated(object): pass

class current_uid(object): pass
class optional(object): pass
class required(object): pass

def urlread(url, data=None, time = 5):
    try:
        return urllib.urlopen(url, data=data).read()
    except:
        if time > 0:
            return urlread(url, data, time - 1)
        else:
            raise

# simple IDL for the xiaonei API
METHODS = {
           'getUsersInfo': ('xiaonei.users.getInfo', [('uids', (comma_separated, current_uid)),
                                                      ('fields', (comma_separated, 'name,sex,hometown_location'))
                                                      ]),
           'getLoggedInUser': ('xiaonei.users.getLoggedInUser', []),
           'isAppAdded': ('xiaonei.users.isAppAdded', [('uid', (int, optional)), ]),
           
           'getXNML': ('xiaonei.profile.getXNML', [('uid', (int, current_uid)), ]),
           'setXNML': ('xiaonei.profile.setXNML', [('uid', (int, required)),
                                                   ('profile', (str, '')),
                                                   ('profile_action', (str, '')),
                                                   ]),
                                                   
           'getFriendsID': ('xiaonei.friends.get', []),
           'getFriendsInfo': ('xiaonei.friends.getFriends', []),
           'areFriends': ('xiaonei.friends.areFriends', [('uids1', (comma_separated, '')),
                                                         ('uids2', (comma_separated, '')),
                                                         ]),
           'getAppUsers': ('xiaonei.friends.getAppUsers', []),
           'getAppFriends': ('xiaonei.friends.getAppFriends', []),
           
           'publishTemplatizedAction': ('xiaonei.feed.publishTemplatizedAction', [('template_id', (int, required)),
                                                                                  ('title_data', (json, optional)), 
                                                                                  ('body_data', (json, optional)), 
                                                                                  ('resource_id', (int, optional)), 
                                                                                  ]),
                                                                                  
           'sendNotifications': ('xiaonei.notifications.send', [('to_ids', (comma_separated, '')),
                                                                ('notification', (str, '')),
                                                                 ]),
            
           'getIsInviters': ('xiaonei.invitations.getIsInviters', [('uids', (comma_separated, '')), ]),                                               
           'getOsInfo': ('xiaonei.invitations.getOsInfo', [('invite_ids', (comma_separated, '')), ]),
           'getUserOsInviteCnt': ('xiaonei.invitations.getUserOsInviteCnt', [('uids', (comma_separated, '')), ]),
           
           'getAllocation': ('xiaonei.admin.getAllocation', []),
           
           'regOrder': ('xiaonei.pay.regOrder', [('order_id', (int, required)), 
                                                 ('amount', (int, required)), 
                                                 ]),
           'isOrderCompleted': ('xiaonei.pay.isCompleted', [('order_id', (int, required)), ]),
           
           'regOrder4Test': ('xiaonei.pay4Test.regOrder', [('order_id', (int, required)), 
                                                           ('amount', (int, required)), 
                                                           ]),
           'isOrderCompleted4Test': ('xiaonei.pay4Test.isCompleted', [('order_id', (int, required)), ]),
           
           }

#def unicode_encode(str):
#    return isinstance(str, unicode) and str.encode('utf-8') or str
#    
#def unicode_urlencode(params):
#    if isinstance(params, dict):
#        params = params.items()
#    return urllib.urlencode([(k, unicode_encode(v)) for k, v in params])

import re
feed_re = re.compile(r'<error_code>.+</error_msg>', re.DOTALL)
feed_re2 = re.compile(r'>(\d+)</feed_publishTemplatizedAction_response>')

    
def generate_api(func):
    api_info = METHODS.get(func.__name__)
    def _wrapped_api_func(self, *args, **kwargs):
        if api_info[0] == 'xiaonei.feed.publishTemplatizedAction':
            format = 'XML'
        else:
            format = RESPONSE_FORMAT
        data = [('api_key', self.api_key), 
                ('session_key', self.session_key), 
                ('v', API_VERSION), 
                ('format', format), 
                ('call_id', self.call_id),
                ('method', api_info[0]),
                ]
        arg_list = api_info[1]
        for i, arg_info in enumerate(arg_list):
            arg_name = arg_info[0]
            try:
                arg_value = kwargs[arg_name]
            except KeyError:
                try:
                    arg_value = args[i]
                except:
                    if arg_info[1][1] == required:
                        raise ArgumentRequiredError, "api %s require argument %s" % (api_info[0], arg_name)
                    elif arg_info[1][1] == optional:
                        continue
                    elif arg_info[1][1] == current_uid:
                        arg_value = self.current_uid
                    else:
                        arg_value = arg_info[1][1]  # it has a default value

            if arg_info[1][0] == comma_separated and not isinstance(arg_value, (str,unicode)):
                arg_value = ",".join(str(i) for i in arg_value)
            if arg_info[1][0] == json:
                if isinstance(arg_value, (tuple, list, dict)):
                    arg_value = simplejson.dumps(arg_value)
            if type(arg_value) == unicode:
                arg_value = arg_value.encode('utf-8')
            data.append((arg_name, arg_value))
#        print `data`
#        data.sort(key = lambda item: item[0])
#        data.append(('sig', self.generate_sig(data)))
        encoded_data = urllib.urlencode(data)
        try:
            res = urlread(XIAONEI_URL, encoded_data)
#            print res
        except Exception, e:
#            print e
            return {}
        if format == 'JSON':
            result = simplejson.loads(res)
#            if isinstance(result, dict) and result.has_key('error_msg'):
#                result['error_msg'] = result['error_msg'].encode('utf-8')
            return result
        else:
            m1 = feed_re.search(res)
            if m1:
                return m1.group(0)
            m2 = feed_re2.search(res)
            if m2:
                return m2.group(1)
            return res
    return _wrapped_api_func

class Xiaonei(object):
    def __init__(self, django_request_obj):
        if isinstance(django_request_obj, HttpRequest):
            request_obj = django_request_obj.REQUEST
        else:
            request_obj = django_request_obj
        self.api_key = request_obj['xn_sig_api_key']
        self.session_key = request_obj['xn_sig_session_key']
        self.current_uid = request_obj['xn_sig_user']
        self.call_id = request_obj['xn_sig_time']

        self.secret_key = settings.SECRET_KEYS[self.api_key]
        self.name = 'xn'
        
    def generate_sig(self, data):
        s = u''.join([u'%s=%s' % (k.decode('utf-8'), v.decode('utf-8')) for k,v in data])
        s = s.encode('utf-8')
        return md5.new(s+self.secret_key).hexdigest()
    
    @generate_api
    def getUsersInfo(self, uids, fields):pass
    
    @generate_api
    def getLoggedInUser(self):pass
    
    @generate_api
    def isAppAdded(self, uid):pass
    
    @generate_api
    def getXNML(self, uid):pass
    
    @generate_api
    def setXNML(self, uid, profile, profile_action):pass
    
    @generate_api
    def getFriendsID(self):pass
    
    @generate_api
    def getFriendsInfo(self):pass
    
    @generate_api
    def areFriends(self, uids1, uids2):pass
    
    @generate_api
    def getAppUsers(self):pass
    
    @generate_api
    def getAppFriends(self):pass
    
    @generate_api
    def publishTemplatizedAction(self, template_id, title_data, body_data, resource_id):pass
    
    @generate_api
    def sendNotifications(self, to_ids, notification):pass
    
    @generate_api
    def getIsInviters(self, uids):pass
    
    @generate_api
    def getOsInfo(self, invite_ids):pass
    
    @generate_api
    def getUserOsInviteCnt(self, uids):pass
    
    @generate_api
    def getAllocation(self):pass
    
    @generate_api
    def regOrder(self, order_id, amount):pass
    
    @generate_api
    def isOrderCompleted(self, order_id):pass
    
    @generate_api
    def regOrder4Test(self, order_id, amount):pass
    
    @generate_api
    def isOrderCompleted4Test(self, order_id):pass